#include "cl_list.h"

cl_list
cl_list_clone(const_cl_list l)
{
	const cll_node * h = l;

	cll_node head;

	cll_node * node = cll_node_create(l->data);
	l = l->next;
	head.next = node;
	while (l != h) {
		node->next = cll_node_create(l->data);
		l = l->next;
		node = node->next;
	}

	node->next = head.next;

	return head.next;
}

void
cl_list_release(cl_list l)
{
	cll_node * h = l;
	cll_node * node = l;
	l = l->next;
	cll_node_release(node);

	while (l != h) {
		node = l;
		l = l->next;
		cll_node_release(node);
	}
}

size_t
cl_list_len(const_cl_list l)
{
	if (!l) {
		return 0;
	}

	const cll_node * h = l;
	size_t len = 1;
	l = l->next;
	while (l != h) {
		++len;
		l = l->next;
	}

	return len;
}

cl_list
cl_list_append(cl_list * lp, elem_t * p, size_t len)
{
	cl_list l = *lp;
	if (!len) {
		return l;
	}

	if (!l) {
		l = cll_node_create(*p++);
		--len;
		l->next = l;
	}

	cll_node * h = l;

	for (; l->next != l; l = l->next) {}

	for (size_t i = len; i; --i) {
		l->next = cll_node_create(*p++);
	}

	l->next = h;

	return *lp;
}

void
cl_list_display(const_cl_list l)
{
	const cll_node * h = l;
	printf(" o| ");
	while (l != h) {
		printf(" --> %d ", l->data);
		l = l->next;
	}
	printf("\n");

}

int
cl_list_get(const_cl_list l, index_t i, elem_t * e)
{
	const cll_node * h = l;
	l = l->next;
	for (index_t ii = 1; ii < i && l != h; ++ii, l = l->next) {}
	return (l != h) ? (*e = l->data, 0) : -1;
}

index_t
cl_list_locate(const_cl_list l, elem_t e)
{
	if (!l) {
		return -1;
	}

	if (l->data ==  e) {
		return 0;
	}

	const cll_node * h = l;
	l = l->next;
	for (index_t ii = 1; l != h; ++ii, l = l->next) {
		if (l->data == e) {
			return ii;
		}
	}

	return -1;
}

l_list
cl_list_reverse(cl_list * lp)
{
	cl_list l = *lp;
	if (!l) {
		return 0;
	}

	cll_node head;
	head.next = l;
	cll_node * tail = head.next;
	cll_node * h = l;
	l = l->next;

	while (l != h) {
		cll_node * node = l;
		l = l->next;
		node->next = head.next;
		head.next = node;
	}

	tail->next = head.next;

	*lp = head.next;

	return head.next;
}

